package com.spsoft.vatoutinv.service.generateinvoice.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.utils.MoneyUtils;
import com.spsoft.core.utils.QRCodeUtil;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.vatoutinv.constants.OfdConstant;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.enums.GenerateInvoiceEnum;
import com.spsoft.vatoutinv.service.vmsfullbswjmanager.VmsFullBswjManagerService;
import com.spsoft.vatoutinv.util.ofd.entity.OriginalInvoice;
import lombok.extern.slf4j.Slf4j;
import org.ofdrw.core.basicStructure.pageObj.layer.Type;
import org.ofdrw.font.Font;
import org.ofdrw.layout.OFDDoc;
import org.ofdrw.layout.PageLayout;
import org.ofdrw.layout.VirtualPage;
import org.ofdrw.layout.element.*;
import org.ofdrw.layout.element.canvas.Canvas;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DecimalFormat;

/**
 * @author wangy
 * @date 2024/3/8 16:33
 */
@Slf4j
@Service
public class CommonInvoice {

    Font kaiFont = new Font("楷体", "楷体");

    Font numFont = new Font("Courier New", "Courier New");


    /**
     * 汉字或中文字符计为2个数值,其他字母,符号,记为1个数值
     *
     * @param text 统计字符串
     * @return 统计数值
     */
    protected static int countCharWidth(String text) {
        if (text == null) {
            return 0;
        }
        int count = 0;
        for (char c : text.toCharArray()) {
            if (isChineseCharacter(c)) {
                count += 2;
            } else {
                count += 1;
            }
        }
        return count;
    }

    /**
     * 根据小数转换成百分比
     */
    protected String calculatePercent(String value) {
        DecimalFormat df = new DecimalFormat("0%");
        return df.format(Double.parseDouble(value));
    }

    /**
     * 判断该字符是否为汉字
     *
     * @param c
     * @return
     */
    protected static boolean isChineseCharacter(char c) {
        Character.UnicodeScript script = Character.UnicodeScript.of(c);
        return script == Character.UnicodeScript.HAN || c == ' ' || c == '；' || c == '：' || c == '，' || c == '。' || c == '、' || c == '（' || c == '）';
    }

    /**
     * 计算所需行数
     *
     * @param num  一行可放开多少个单位
     * @param text 文字
     */
    protected static int calculateRow(int num, String text) {
        int row = 0;
        int temp = countCharWidth(text);
        if (temp % num == 0) {
            row = temp / num;
        } else {
            row = temp / num + 1;
        }

        return row;
    }

    /**
     * 计算居中显示坐标
     *
     * @param paragraphWidth 当前区域宽度
     * @param initX          初始X坐标
     * @param temp           当前文字
     * @return
     */
    protected Double calculateCenter(Double paragraphWidth, Double initX, String temp) {
        return initX + (paragraphWidth / 2) - (countCharWidth(temp) * 1.5) / 2;
    }

    /**
     * 计算居右显示坐标
     *
     * @param paragraphWidth 当前区域宽度
     * @param initX          初始X坐标
     * @param temp           当前文字
     * @return
     */
    protected Double calculateRight(Double paragraphWidth, Double initX, String temp) {
        return (initX + paragraphWidth) - (countCharWidth(temp) * 1.5);
    }

    /**
     * 计算居右显示坐标
     *
     * @param paragraphWidth 当前区域宽度
     * @param initX          初始X坐标
     * @param len            当前文字
     * @return
     */
    protected Double calculateRight(Double paragraphWidth, Double initX, int len) {
        return (initX + paragraphWidth) - (len * 1.5);
    }


    /**
     * 生成二维码图片
     *
     * @param graphCode 二维码内容
     * @param path      二维码保存路径
     * @return
     */
    protected Img buildECodeImg(String graphCode, String path) {
        path = path.substring(0, path.lastIndexOf(File.separator));

        BufferedImage bufferedImage = QRCodeUtil.crateQRCode(graphCode, 300, 300, "image/logo.png", 64, 64);
        Img result = null;
        try {
            ImageIO.write(bufferedImage, "png", Paths.get(path + File.separator + "eCode.png").toFile());
            Path eCodePath = Paths.get(path, "eCode.png");
            result = new Img(eCodePath);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(ResponseEnum.INVOICE_DOWNLOAD_FAIL_04);
        }
        return result;
    }

    /**
     * 当n≤8 行时，发票高度140mm，每条发票明细行款高度4.375mm；
     * 当8<n≤12行时，发票高度增加17.5mm，不换页；
     * 当12<n≤16行时，发票高度增加17.5mm，不换页；
     * 当16<n≤20行时，发票高度增加17.5mm，不换页；
     * 当20<n≤24行时，发票高度增加17.5mm，不换页；
     * 当24<n≤28行时，发票高度增加17.5mm，不换页；
     * 当28<n≤32行时，发票高度增加17.5mm，不换页；
     * 当32<n≤36行时，发票高度增加17.5mm，不换页；
     * 当36<n≤40行时，发票高度增加17.5mm，不换页；
     * 当40<n≤42行时，发票高度增加8.75mm，不换页；
     * 当42<n≤47行时，发票高度不变，取最后一行明细信息换页处理，每页含有“票头”、
     * “销售方和购买方信息”、“应税明细信息”和“票尾”信息，其中“价税合计（大写）”
     * 和“备注”模块只在末页展示
     * 通过行数计算出页面所需高度
     */
    protected static double calculatePageHeight(int n) {
        double height = 0;
        if (n <= 8) {
            height = 140;
        } else if (n <= 12) {
            height = 157.5;
        } else if (n <= 16) {
            height = 175;
        } else if (n <= 20) {
            height = 192.5;
        } else if (n <= 24) {
            height = 210;
        } else if (n <= 28) {
            height = 227.5;
        } else if (n <= 32) {
            height = 245;
        } else if (n <= 36) {
            height = 262.5;
        } else if (n <= 40) {
            height = 280;
        } else if (n <= 42) {
            height = 288.75;
        } else if (n <= 47) {
            height = 288.75;
        }
        return height;
    }


    protected void buildHeadTitle(VirtualPage virtualPage, OriginalInvoice originalInvoice, int pageSize, int pageIndex, String outPath) throws IOException {
        // 二维码
        Paragraph eCodeP = new Paragraph(30D, 30D);
        eCodeP.setBorder(0.25d);
        eCodeP.setBorderColor(139, 0, 15);
        eCodeP.setWidth(20D);
        eCodeP.setHeight(20D);
        eCodeP.setXY(7D, 6D);
        eCodeP.setPosition(Position.Absolute);
        eCodeP.setLayer(Type.Background);


        // 生成二维码
        Img eCode = buildECodeImg(originalInvoice.getGraphCode(), outPath);
        eCode.setPosition(Position.Absolute)
                .setX(7D)
                .setY(6D)
                .setHeight(20D)
                .setWidth(20D)
                .setLayer(Type.Body);
        virtualPage.add(eCode);
        // 标签
        // 判断是否为差额开票
        boolean ceFlag = false;
        boolean tdysFlag = false;
        if (StringUtil.isNotEmpty(originalInvoice.getTaxationMethod())) {
            ceFlag = true;
        }
        // 判断是否为特定要素
        if (StringUtil.isNotEmpty(originalInvoice.getTdys()) && !GenerateInvoiceEnum.BASE_INVOICE.getCode().equals(originalInvoice.getTdys())) {
            tdysFlag = true;
        }

        // 特定要素
        if (ObjectUtil.isNotEmpty(GenerateInvoiceEnum.getByCode(originalInvoice.getTdys()))) {

            if (!originalInvoice.getTdys().equals(GenerateInvoiceEnum.BASE_INVOICE.getCode())) {
                String tdys = GenerateInvoiceEnum.getByCode(originalInvoice.getTdys()).getName();
                // 特定要素 标签
                final Span tdywTextSpan = new Span(tdys)
                        .setFontSize(3D);
                Paragraph tdywTextP = new Paragraph(28D, 13D).add(tdywTextSpan);
                tdywTextP.setPosition(Position.Absolute)
                        .setLayer(Type.Body);
                if (ceFlag && tdysFlag) {
                    tdywTextP.setXY(calculateCenter(28d, 29D, tdys), 10D);
                } else {
                    tdywTextP.setXY(calculateCenter(28d, 29D, tdys), 13D);
                }
                virtualPage.add(tdywTextP);
            }

            if (ceFlag) {
                String tempSpan = "";
                if (CommonEnum.CEZS_01.getKey().equals(originalInvoice.getTaxationMethod())) {
                    tempSpan = "差额征税-全额开票";
                } else {
                    tempSpan = "差额征税-差额开票";
                }
                // 基础发票标签
                final Span baseInvoiceSpan = new Span(tempSpan)
                        .setFontSize(3D);
                Paragraph baseInvoiceP = new Paragraph(28D, 13D).add(baseInvoiceSpan);
                baseInvoiceP.setPosition(Position.Absolute)
                        .setLayer(Type.Body);
                if (tdysFlag) {
                    baseInvoiceP.setXY(calculateCenter(28d, 29D, tempSpan), 14D);
                } else {
                    baseInvoiceP.setXY(calculateCenter(28d, 29D, tempSpan), 13D);
                }
                virtualPage.add(baseInvoiceP);
            }
        }


        // 整体宽度为210,内容可能为 电子发票（普通发票）或 电子发票（增值税专用发票）
        String invoiceTitle = "电子发票（增值税专用发票）";
        double titleX = 63D;
        double titleY = 8D;
        if (CommonEnum.INVOICE_TYPE_02.getKey().equals(originalInvoice.getInvoiceType())) {
            invoiceTitle = "电子发票（普通发票）";
            titleX = 75D;
        }
        Span invoiceTitleSpan = new Span(invoiceTitle)
                .setFont(kaiFont)
                .setFontSize(7D)
                .setColor(139, 0, 15);

        // 标题
        Paragraph titleP = new Paragraph(98D, 20D).add(invoiceTitleSpan);
        titleP.setBorderColor(139, 0, 15);
        titleP.setXY(titleX, titleY);
        titleP.setPosition(Position.Absolute);
        titleP.setLayer(Type.Background);
        virtualPage.add(titleP);

        // 发票下划线
        Paragraph lineP = new Paragraph(68D, 0.2D);
        lineP.setBorderTop(0.25d);
        lineP.setBorderBottom(0.25D);
        lineP.setBorderColor(139, 0, 15);
        lineP.setXY(72D, titleY + 10D);
        lineP.setHeight(1D);
        lineP.setPosition(Position.Absolute);
        lineP.setLayer(Type.Background);
        virtualPage.add(lineP);


        VmsFullBswjManagerService fullBswjManagerService = SpringUtil.getBean(VmsFullBswjManagerService.class);
        String filepath = fullBswjManagerService.filePath(originalInvoice.getDeptCode());
        File imgFile = new File(filepath);
        if (!imgFile.exists()) {
            log.error("印章文件不存在:{}", filepath);
            throw new BusinessException(ResponseEnum.LAYOUT_FILE_NOT_FOUND);
        }
        Path bswjyz = Paths.get(filepath);
        Img img = new Img(bswjyz);
        img.setPosition(Position.Absolute)
                .setX(90D)
                .setY(9D)
                .setHeight(20D)
                .setWidth(30D)
                .setLayer(Type.Body);
        virtualPage.add(img);


        // 发票号码 标签
        Span invoiceNoLabelSpan = new Span("发票号码:")
                .setFont(kaiFont)
                .setFontSize(3D)
                .setColor(139, 0, 15);
        Paragraph invoiceNoTitleP = new Paragraph(15D, 6D).add(invoiceNoLabelSpan);
        invoiceNoTitleP.setPosition(Position.Absolute)
                .setXY(155D, 9D)
                .setLayer(Type.Body)
        ;
        virtualPage.add(invoiceNoTitleP);


        // 发票号码文字
        Span invoiceNoTextSpan = new Span(originalInvoice.getInvoiceNo())
                .setFontSize(3D)
                .setColor(0, 0, 0);
        Paragraph invoiceNoTextP = new Paragraph(40D, 6D).add(invoiceNoTextSpan);
        invoiceNoTextP.setPosition(Position.Absolute)
                .setXY(170D, 9D)
                .setLayer(Type.Body);
        virtualPage.add(invoiceNoTextP);


        // 开票日期标签
        final Span invoiceDateLableSpan = new Span("开票日期:")
                .setFont(kaiFont)
                .setFontSize(3D)
                .setColor(139, 0, 15);
        Paragraph invoiceDateTitleP = new Paragraph(15D, 6D).add(invoiceDateLableSpan);
        invoiceDateTitleP.setPosition(Position.Absolute)
                .setXY(155D, 15D)
                .setLayer(Type.Body);
        virtualPage.add(invoiceDateTitleP);
        // 发票日期文字
        Span invoiceDateTextSpan = new Span(originalInvoice.getIssueDate())
                .setFontSize(3D)
                .setColor(0, 0, 0);
        Paragraph invoiceDateTextP = new Paragraph(40D, 6D).add(invoiceDateTextSpan);
        invoiceDateTextP.setPosition(Position.Absolute)
                .setXY(170D, 15D)
                .setLayer(Type.Body)
        ;
        virtualPage.add(invoiceDateTextP);

        // 页数
        if (pageSize > 1) {
            Span pageSpan = new Span("共" + pageSize + "页 第" + pageIndex + "页")
                    .setFontSize(3D)
                    .setColor(0, 0, 0);
            Paragraph pageP = new Paragraph(30D, 6D).add(pageSpan);
            pageP.setPosition(Position.Absolute)
                    .setXY(189D, 26D)
                    .setLayer(Type.Body)
            ;
            virtualPage.add(pageP);
        }

    }


    protected void buildBuyerSeller(VirtualPage virtualPage, OriginalInvoice originalInvoice) {
        // 购买方
        Paragraph buyerP = new Paragraph(100.5D, 22D);
        buyerP.setBorder(0.25d);
        buyerP.setBorderColor(139, 0, 15);
        buyerP.setBorderBottom(0D);
        buyerP.setXY(4.5D, 30D);
        buyerP.setPosition(Position.Absolute);
        buyerP.setLayer(Type.Background);
        virtualPage.add(buyerP);

        Paragraph buyerDivP = new Paragraph(6D, 22D);
        buyerDivP.setBorder(0.25D);
        buyerDivP.setBorderColor(139, 0, 15);
        buyerDivP.setBorderBottom(0D);
        buyerDivP.setXY(4.5D, 30D);
        buyerDivP.setPosition(Position.Absolute);
        buyerDivP.setLayer(Type.Background);
        virtualPage.add(buyerDivP);


        // 购买方标题
        Span buyerTitleSpan = new Span("购\n买\n方\n信\n息")
                .setFont(kaiFont)
                .setFontSize(3D)
                .setColor(139, 0, 15);
        Paragraph buyerTitleP = new Paragraph(5D, 22D).add(buyerTitleSpan);
        buyerTitleP.setXY(4.5D, 30D);
        buyerTitleP.setPaddingLeft(1.5D);
        buyerTitleP.setPaddingTop(1D);
        buyerTitleP.setPosition(Position.Absolute);
        buyerTitleP.setLayer(Type.Background);
        buyerTitleP.setLineSpace(0.2D);
        virtualPage.add(buyerTitleP);

        // 购买方名称 统一社会信用代码/纳税人识别号
        Span buyerNameTitleSpan = new Span("名称:\n\n\n\n\n\n\n\n\n\n统一社会信用代码/纳税人识别号:")
                .setFont(kaiFont)
                .setFontSize(3D)
                .setColor(139, 0, 15);
        Paragraph buyerNameTitleP = new Paragraph(80D, 30D).add(buyerNameTitleSpan);
        buyerNameTitleP.setPosition(Position.Absolute)
                .setXY(11.5D, 32.5D)
                .setLineSpace(0.7D)
                .setLayer(Type.Background)
        ;
        virtualPage.add(buyerNameTitleP);

        // 购买人名称
        Span buyerNameSpan = new Span(originalInvoice.getBuyerName())
                .setFontSize(3D)
                .setColor(0, 0, 0);
        Paragraph buyerNameP = new Paragraph(80D, 10D).add(buyerNameSpan);
        buyerNameP.setPosition(Position.Absolute)
                .setXY(18.5D, 32.5D)
                .setLayer(Type.Background)
        ;
        virtualPage.add(buyerNameP);

        // 购买人 纳税人识别号
        if (StringUtil.isNotEmpty(originalInvoice.getBuyerTaxID())) {
            Span buyerTaxNoSpan = new Span(originalInvoice.getBuyerTaxID())
                    .setFont(numFont)
                    .setFontSize(4D)
                    .setColor(0, 0, 0);
            Paragraph buyerTaxNoP = new Paragraph(45D, 10D).add(buyerTaxNoSpan);
            buyerTaxNoP.setPosition(Position.Absolute)
                    .setXY(56.5D, 42D)
                    .setLayer(Type.Background)
            ;
            virtualPage.add(buyerTaxNoP);
        }


        // 销售方
        Paragraph sellerP = new Paragraph(100.5D, 22D);
        sellerP.setBorder(0.25D);
        sellerP.setBorderColor(139, 0, 15);
        sellerP.setBorderBottom(0D);
        sellerP.setBorderLeft(0D);
        sellerP.setXY(105D, 30D);
        sellerP.setPosition(Position.Absolute);
        sellerP.setLayer(Type.Background);
        virtualPage.add(sellerP);

        Paragraph sellerDivP = new Paragraph(6D, 22D);
        sellerDivP.setBorder(0.25D);
        sellerDivP.setBorderColor(139, 0, 15);
        sellerDivP.setBorderBottom(0D);
        sellerDivP.setBorderLeft(0D);
        sellerDivP.setXY(105D, 30D);
        sellerDivP.setPosition(Position.Absolute);
        sellerDivP.setLayer(Type.Background);
        virtualPage.add(sellerDivP);

        // 销售方标题框
        Span sellerTitleSpan = new Span("销\n售\n方\n信\n息")
                .setFont(kaiFont)
                .setFontSize(3D)
                .setColor(139, 0, 15);
        Paragraph sellerTitleP = new Paragraph(6D, 22D).add(sellerTitleSpan);
        sellerTitleP.setXY(105D, 30D);
        sellerTitleP.setPaddingLeft(1.5D);
        sellerTitleP.setPaddingTop(1D);
        sellerTitleP.setLineSpace(0.2D);
        sellerTitleP.setPosition(Position.Absolute);
        sellerTitleP.setLayer(Type.Background);
        virtualPage.add(sellerTitleP);

        // 销售方名称 统一社会信用代码/纳税人识别号
        Span sellerNameTitleSpan = new Span("名称:\n\n\n\n\n\n\n\n\n\n统一社会信用代码/纳税人识别号:")
                .setFont(kaiFont)
                .setFontSize(3D)
                .setColor(139, 0, 15);
        Paragraph sellerNameTitleP = new Paragraph(80D, 30D).add(sellerNameTitleSpan);
        sellerNameTitleP.setPosition(Position.Absolute)
                .setXY(111.5D, 32.5D)
                .setLineSpace(0.7D)
                .setLayer(Type.Background)
        ;
        virtualPage.add(sellerNameTitleP);

        // 销售方名称
        Span sellerNameSpan = new Span(originalInvoice.getSellerName())
                .setFontSize(3D)
                .setColor(0, 0, 0);
        Paragraph sellerNameP = new Paragraph(80D, 10D).add(sellerNameSpan);
        sellerNameP.setPosition(Position.Absolute)
                .setXY(118.5D, 32.5D)
                .setLayer(Type.Background)
        ;
        virtualPage.add(sellerNameP);

        // 销售方 纳税人识别号
        Span sellerTaxNoSpan = new Span(originalInvoice.getSellerTaxID())
                .setFont(numFont)
                .setFontSize(4D)
                .setColor(0, 0, 0);
        Paragraph sellerTaxNoP = new Paragraph(45D, 10D).add(sellerTaxNoSpan);
        sellerTaxNoP.setPosition(Position.Absolute)
                .setXY(156.5D, 42D)
                .setLayer(Type.Background)
        ;
        virtualPage.add(sellerTaxNoP);
    }


    protected void buildBottom(VirtualPage virtualPage, OriginalInvoice originalInvoice, BigDecimal subTotalAmount, BigDecimal subTotalTaxAmount, boolean isLastPage, double pageHeight, Canvas canvas) {
        // 如果不是最后一页 显示小计
        if (isLastPage) {
            // 价税合计 宽度60
            Paragraph totalAmountLeftP = new Paragraph(60D, 8D);
            totalAmountLeftP.setBorder(0.25D);
            totalAmountLeftP.setBorderColor(139, 0, 15);
            totalAmountLeftP.setXY(4.5D, pageHeight - 44D);
            totalAmountLeftP.setPosition(Position.Absolute);
            totalAmountLeftP.setLayer(Type.Background);
            virtualPage.add(totalAmountLeftP);
            Span totalAmountTextSpan = new Span("          价税合计(大写):")
                    .setFont(kaiFont)
                    .setFontSize(3D)
                    .setColor(139, 0, 15);
            Paragraph totalAmountTextP = new Paragraph(60D, 8D);
            totalAmountTextP.setXY(4.5D, pageHeight - 44D);
            totalAmountTextP.setPaddingTop(2D);
            totalAmountTextP.setPosition(Position.Absolute);
            totalAmountTextP.setLayer(Type.Background);
            totalAmountTextP.add(totalAmountTextSpan);
            virtualPage.add(totalAmountTextP);

            // 价税合计右侧
            Paragraph totalAmountRightP = new Paragraph(141D, 8D);
            totalAmountRightP.setBorder(0.25D);
            totalAmountRightP.setBorderColor(139, 0, 15);
            totalAmountRightP.setBorderLeft(0D);
            totalAmountRightP.setBorderRight(0D);
            totalAmountRightP.setXY(64.5, pageHeight - 44D);
            totalAmountRightP.setPosition(Position.Absolute);
            totalAmountRightP.setLayer(Type.Background);
            virtualPage.add(totalAmountRightP);


            // 价税合计大写 内容
            canvas.setXY(64.5, pageHeight - 42D);
            Span totalAmountSpan = new Span(MoneyUtils.toChinese(originalInvoice.getTaxInclusiveTotalAmount()))
                    .setFontSize(3D)
                    .setColor(0, 0, 0);
            Paragraph totalAmountP = new Paragraph(86D, 8D);
            totalAmountP.setXY(69.5, pageHeight - 44D);
            totalAmountP.setPaddingTop(2D);
            totalAmountP.setPosition(Position.Absolute);
            totalAmountP.setLayer(Type.Background);
            totalAmountP.add(totalAmountSpan);
            virtualPage.add(totalAmountP);

            // 价税合计 小写
            Span totalAmountSmallSpan = new Span("(小写):")
                    .setFont(kaiFont)
                    .setFontSize(3D)
                    .setColor(139, 0, 15);
            Span totalAmountSmallSpan2 = new Span(originalInvoice.getTaxInclusiveTotalAmount())
                    .setFontSize(3D)
                    .setColor(0, 0, 0);
            Paragraph totalAmountSmallP = new Paragraph(50.5D, 8D);
            totalAmountSmallP.setXY(150.5D, pageHeight - 44D);
            totalAmountSmallP.setPaddingTop(2D);
            totalAmountSmallP.setPosition(Position.Absolute);
            totalAmountSmallP.setLayer(Type.Background);
            totalAmountSmallP.add(totalAmountSmallSpan);
            totalAmountSmallP.add(totalAmountSmallSpan2);
            virtualPage.add(totalAmountSmallP);


            // 备注左侧标题 宽度6
            Span remarkLeftSpan = new Span("备\n注")
                    .setFont(kaiFont)
                    .setFontSize(3D)
                    .setColor(139, 0, 15);
            Paragraph remarkLeftP = new Paragraph(6D, 20D);
            remarkLeftP.setXY(4.5D, pageHeight - 36D);
            remarkLeftP.setPosition(Position.Absolute);
            remarkLeftP.setLayer(Type.Background);
            remarkLeftP.setPaddingTop(5D);
            remarkLeftP.setPaddingLeft(1.5D);
            remarkLeftP.add(remarkLeftSpan);
            virtualPage.add(remarkLeftP);

            Paragraph remarkRightP = new Paragraph(195D, 20D);
            remarkRightP.setBorder(0.25D);
            remarkRightP.setBorderColor(139, 0, 15);
            remarkRightP.setBorderTop(0D);
            remarkRightP.setBorderRight(0D);
            remarkRightP.setBorderBottom(0D);
            remarkRightP.setXY(10.5D, pageHeight - 35.5D);
            remarkRightP.setPosition(Position.Absolute);
            remarkRightP.setLayer(Type.Background);
            remarkRightP.setLineSpace(0.2D);
            virtualPage.add(remarkRightP);

            if (StringUtil.isNotEmpty(originalInvoice.getNote())) {
                // 备注字体大小
                double noteFontSize = 3D;
                // 备注右侧内容  130个字符
                String note = originalInvoice.getNote();
                String[] split = note.split("\n");
                int noteRow = 0;
                // 遍历备注
                for (String text : split) {
                    // 先查看是否超过五行
                    noteRow += calculateRow(130, text);
                }
                // 如果超过五行 缩小字体 2号字体可添加 194个字符
                if (noteRow > 5) {
                    // 设置字体为2号
                    noteFontSize = 2D;
                    // 重置备注所需行数
                    noteRow = 0;
                    // 继续判断 2号字体是否超过五行
                    for (String text : split) {
                        noteRow += calculateRow(194, text);
                    }
                    // 如果缩小字体还是大于五行 还原3号字体
                    if (noteRow > 8) {
                        // 设置字体为3号
                        noteFontSize = 3D;
                        // 重置备注所需行数
                        noteRow = 0;
                        // 拼接所有字符串
                        note = note.replace("\n", "    ");
                        // 查看去除换行后 是否还会大于五行
                        noteRow += calculateRow(130, note);
                        // 如果还是大于五行 就缩小字体
                        if (noteRow > 5) {
                            // 设置字体为2号
                            noteFontSize = 2D;
                        }
                    }
                }
                Span remarkRightSpan = new Span(note)
                        .setFontSize(noteFontSize)
                        .setColor(0, 0, 0);
                remarkRightP.add(remarkRightSpan);
            }
        }
        // 开票人
        Span drawerSpan = new Span("           开票人：")
                .setFont(kaiFont)
                .setFontSize(3D)
                .setColor(139, 0, 15);
        Span drawerSpan2 = new Span(originalInvoice.getInvoiceClerk())
                .setFontSize(3D)
                .setColor(0, 0, 0);
        Paragraph drawerP = new Paragraph(201D, 6D);
        drawerP.setXY(4.5D, pageHeight - 11.5D);
        drawerP.setPosition(Position.Absolute);
        drawerP.setLayer(Type.Background);
        drawerP.add(drawerSpan);
        drawerP.add(drawerSpan2);
        virtualPage.add(drawerP);
    }

    protected void buildNewPageNote(OFDDoc ofdDoc, OriginalInvoice originalInvoice, String outPath) throws IOException {
        // 开始创建页面
        PageLayout pageLayout = ofdDoc.getPageLayout();
        // 设置页面宽度
        pageLayout.setWidth(OfdConstant.INVOICE_MIN_WIDTH);
        // 设置页面高度
        pageLayout.setHeight(140D);
        // 创建虚拟页面
        VirtualPage virtualPage = new VirtualPage(pageLayout);

        // 构建头部标题
        buildHeadTitle(virtualPage, originalInvoice, 1, 1, outPath);

        // 构建 购买人 销售人
        buildBuyerSeller(virtualPage, originalInvoice);

        // 构建主体
        Span note = new Span("货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称货物或应税劳务、服务名称")
                .setFont(kaiFont)
                .setFontSize(3D)
                .setColor(0, 0, 0);
        Paragraph noteP = new Paragraph(200.75D, 72D);
        noteP.setXY(4.5D, 52.1D);
        noteP.setPosition(Position.Absolute);
        noteP.setLayer(Type.Background);
        noteP.add(note);
        virtualPage.add(noteP);

        // 构建两侧边框 发票识别线
        buildBoderLine(virtualPage, 140D);

        // 开票人
        Span drawerSpan = new Span("           开票人：")
                .setFont(kaiFont)
                .setFontSize(3D)
                .setColor(139, 0, 15);
        Span drawerSpan2 = new Span(originalInvoice.getInvoiceClerk())
                .setFontSize(3D)
                .setColor(0, 0, 0);
        Paragraph drawerP = new Paragraph(201D, 6D);
        drawerP.setXY(4.5D, 128.5D);
        drawerP.setPosition(Position.Absolute);
        drawerP.setLayer(Type.Background);
        drawerP.add(drawerSpan);
        drawerP.add(drawerSpan2);
        virtualPage.add(drawerP);

        // 添加到文档
        ofdDoc.addVPage(virtualPage);
    }

    protected void buildBoderLine(VirtualPage virtualPage, double pageHeight) {
        // 绘制两侧边框
        Div div = new Div();
        div.setBorder(0.25D);
        div.setBorderColor(139, 0, 15);
        div.setWidth(200.75D);
        div.setHeight(pageHeight - 68);
        div.setLayer(Type.Background);
        div.setXY(4.5D, 52D);
        div.setPosition(Position.Absolute);
        virtualPage.add(div);

        /*
         票面右框线1/2以下位置增加
         金色色带（RGB：R246、G237、B225）
         咖色色带（RGB：R118、G89、B84）
         色带高度均为 0.54mm，长度为右框线的1/2
        */

        double lineHeight = pageHeight - 46;

        Div rightDivTop = new Div();
        rightDivTop.setBorder(0.25D);
        rightDivTop.setBorderColor(246, 237, 225);
        rightDivTop.setBackgroundColor(246, 237, 225);
        rightDivTop.setWidth(0.2D);
        rightDivTop.setHeight(lineHeight / 2);
        rightDivTop.setLayer(Type.Background);
        rightDivTop.setXY(205.75D, 30D);
        rightDivTop.setPosition(Position.Absolute);
        virtualPage.add(rightDivTop);

        Div rightDivBottom = new Div();
        rightDivBottom.setBorder(0.25D);
        rightDivBottom.setBorderColor(118, 89, 84);
        rightDivBottom.setBackgroundColor(118, 89, 84);
        rightDivBottom.setWidth(0.2D);
        rightDivBottom.setHeight(lineHeight / 2);
        rightDivBottom.setLayer(Type.Background);
        rightDivBottom.setXY(205.75D, (lineHeight / 2) + 30);
        rightDivBottom.setPosition(Position.Absolute);
        virtualPage.add(rightDivBottom);

    }

}
